package spacetrussOpt;

import core_masterworker.Worker;
import geneticalgorithm_masterworker.GAGenetic;
import inf.minife.fe.Model;
import utils.MWUtils;
import data.DataTest;
import model.SpaceTruss;
import mpi.MPI;
import mpi.Status;

public class SPGAWorker extends Worker {

	/* Tag information between master - worker */
	public MWUtils mwutils = new MWUtils();
	final int work_tag = mwutils.WORK_TAG;
	final int data_tag = mwutils.DATA_TAG;
	final int stop_tag = mwutils.STOP_TAG;
	
	public SPGAWorker(int id_) {
		super(id_);
		
	}	
	
	public void doWork(int myid, int components, int master, DataTest[] listbcast,
			SpaceTruss spacetruss, double sigmaMax, double uMax, int numberofgene, 
			float crossoverfactor, float mutationfactor, int result_number){
		
		Status status;
		boolean done = false;		
		
		/* Store data */
		int cid = 0;
		
		int num_genes = numberofgene;		
		int num_chrome = components;
		
		float crossover_fraction = crossoverfactor;
		float mutation_fraction = mutationfactor;

		GAGenetic genetic_experiment = new GAGenetic(num_genes, num_chrome, crossover_fraction, mutation_fraction);
		
		/* Set up for dynamic assignment */
		DataTest[] count = new DataTest[1];
		count[0] = new DataTest(cid);	
		
		/* Initiate result worker send to master */
		DataTest[] result = new DataTest[result_number];
		
		/* Init result */
		for(int i = 0; i < result.length; i++){
			result[i] = new DataTest(0);			
		}
		
		/* Init a double array to store new cross section area values */
		double[] x = new double[num_chrome];
		double[] list_area = new double[listbcast.length];
		
		try{
			for(int i = 0; i < list_area.length; i++){
				list_area[i] = listbcast[i].getDataDouble();
			}
		}
		catch (IndexOutOfBoundsException e) {
			System.out.println("Index out of boundary! Check use in list area array length");
			return;
		}
		catch (NullPointerException e) {
			System.out.println("List area is null pointer! Init before use");
			return;
		}

		while(done != true){
			status = MPI.COMM_WORLD.Recv(count, 0, count.length, MPI.OBJECT, master, MPI.ANY_TAG);
			
			/* Checking received data */
			int the_row = (int)count[0].getDataInt();
			System.out.println("Receive count at = " + the_row);
			System.out.println("Worker number = " + myid);
			System.out.println("Tag = " + status.tag + " from source = " + status.source);
			
			if(status.tag == stop_tag){
				done = true;
				break;
			}		

			
			/*
			 * Call the Genetic Algorithm to generate
			 * a set of numbers that represents location of cross section area
			 * values in list of area
			 * After that, we take a set of number
			 * match with values of area from list of area
			 * pass to Plane Truss model to check fitness value
			 * mass value and constrain conditions
			 */		    
		
			genetic_experiment.evolve();
			
	    	/* Match individual of generation with component in list of cross section area */
	    	for (int j = 0; j < num_chrome; j++) {
	    		int temp = (int)genetic_experiment.getValue(j);
	    		x[j] = list_area[temp];
	            System.out.print("[" + temp + "] " );         
	        }
	    	
	    	/* Update to plane truss and calculate */
	    	Model evaluation = new Model();
	    	evaluation = spacetruss.createModel(x);
	    	evaluation.solve();
	    	double mass_new = evaluation.getTotalMass();
	    	System.out.println("New mass value = " + mass_new);
	    	
	    	/* Check fitness condition 
	    	 * Function: F(x) = 1/f(x)[1000v + 1]
	    	 * with f(x) = total mass
	    	 */
	    	
	    	/* Normalize form of stress constrain
	    	 * sigma(j)/sigmaMax - 1 <= 0
	    	 */
	    	/* Check violation stress constrains */
	    	double[] fcheck = mwutils.computeStressConstrains(evaluation, sigmaMax);
	    	double countviolation = 0;
	    	for(int j = 0; j < fcheck.length; j++){
	    		if(fcheck[j] > 0) countviolation++;
	    	}
	    	
	    	/* Normalize form of displacement constrain
	    	 * u(j)/uMax - 1 <= 0
	    	 */
	    	/* Check violation stress constrains */
	    	/* Check violation displacement constrains */
	    	double[] gxcheck = mwutils.computeDispXConstrains(evaluation, uMax);
	    	
	    	for(int j = 0; j < gxcheck.length; j++){
	    		if(gxcheck[j] > 0) countviolation++;
	    	}
	    	double[] gycheck = mwutils.computeDispYConstrains(evaluation, uMax);
	    	
	    	for(int j = 0; j < gycheck.length; j++){
	    		if(gycheck[j] > 0) countviolation++;
	    	}
	    	System.out.println("Number of violation constrains = " + countviolation);
	    	
	    	/* Calculate fitness value */
	    	double fitvalue = 1/((1000.0*countviolation + 1)*mass_new);
	    	genetic_experiment.setFitnessValue(fitvalue);
	    
	    	System.out.println("Generation's fitness value = " + genetic_experiment.getFitnessValue());
	    	System.out.println();
	    	
	    	/* Store values
	    	 * no of generation
	    	 * number of violation constrain
	    	 * fitness value
	    	 * mass value
	    	 * to send back to master
	    	 */
	    	try{
	    		result[0].updateData(the_row);
				result[1].updateData(countviolation);
				result[2].updateData(fitvalue);
				result[3].updateData(mass_new);
	    	}
	    	catch (IndexOutOfBoundsException e) {
				System.out.println("Index out of boundary! Check use in result array length");
				return;
			}
			catch (NullPointerException e) {
				System.out.println("Result array is null pointer! Init before use");
				return;
			}
			
			/* Send result to master */
			MPI.COMM_WORLD.Send(result, 0, result.length, MPI.OBJECT, master, data_tag);
		}
	}	
	

	@Override
	public void doWork() {
		// TODO Auto-generated method stub
		
	}

}
